package com.wosaitech.baby.dao;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Repository;

import com.wosaitech.baby.utils.GodUtils;

@Repository
public class BaseDAO {

	protected Session session;

	@Autowired
	protected SessionFactory sessionFactory;

	public Session getSession() {
		return sessionFactory.getCurrentSession();
	}

	public void flush() {
		getSession().flush();
	}

	public void clear() {
		getSession().clear();
	}

	public void save(Object entity) {
		getSession().save(entity);
		flush();
	}

	public void update(Object entity) {
		getSession().update(entity);
		flush();
	}

	public void saveOrUpdate(Object entity) {
		getSession().saveOrUpdate(entity);
		flush();
	}

	public void saveOrUpdateAll(List<?> entities) {
		if (entities == null || entities.isEmpty()) {
			return;
		}
		for (Object ojb : entities) {
			this.saveOrUpdate(ojb);
		}
	}

	public void delete(Object entity) {
		getSession().delete(entity);
		flush();
	}

	public void deleteAll(List<?> entities) {
		if (entities == null || entities.isEmpty()) {
			return;
		}
		for (Object object : entities) {
			getSession().delete(object);
		}
	}

	/**
	 * 执行查询语句（HQL）。
	 * 
	 * @param queryStr
	 *            查询语句HQL。
	 * @return 查询结果。
	 */
	public List<?> query(String queryStr) {
		return this.find(queryStr);
	}

	/**
	 * 执行查询语句（HQL）。
	 * 
	 * @param queryStr
	 *            查询语句HQL。
	 * @param params
	 *            参数值。
	 * @return 查询结果。
	 */
	public List<?> query(String queryStr, Map<?, ?>... map) {
		return this.find(queryStr, map);
	}

	public List<?> query(final String queryStr, final PageBean pageBean) {
		if (pageBean == null) {
			return query(queryStr);
		}
		Map<String, String> objMap = new HashMap<String, String>();
		long recordCount = this.getRowCount(queryStr, objMap);
		pageBean.setRecordCount(recordCount);
		// return this.query(queryStr,pageBean);
		return this.find(queryStr, pageBean, objMap);
	}

	/**
	 * 分页查询对象
	 * 
	 * @param queryStr
	 *            查询语句
	 * @param params
	 *            参数值
	 * @param pageBean
	 *            分页对象
	 * @return 记录结果
	 */
	public List<?> query(final String queryStr, final PageBean pageBean,
			final Map<?, ?>... map) {
		if (pageBean == null) {
			return query(queryStr, map);
		}
		long recordCount = this.getRowCount(queryStr, map);
		pageBean.setRecordCount(recordCount);
		List<?> result = find(queryStr, pageBean, map);
		return result;
	}

	/**
	 * 查询出单个对象。
	 * 
	 * @param queryString
	 *            查询语句。
	 * @param params
	 *            参数值。
	 */
	public Object getSingle(String queryString, Map<?, ?>... map) {
		List<?> list = this.find(queryString, map);

		if (list.size() > 0) {
			return list.iterator().next();
		} else {
			return null;
		}
	}

	/**
	 * 根据对象类型和ID查询一个对象。
	 * 
	 * @param entityClass
	 *            要查询的实体类。
	 * @param id
	 *            对象标识。
	 * @return 查询结果。
	 * @throws DataAccessException
	 */
	public Object getObjectById(Class<?> entityClass, Serializable id)
			throws DataAccessException {
		Object object = getSession().get(entityClass, id);
		return object;
	}

	/**
	 * 根据给定的查询语句HQL删除实体。
	 * 
	 * @param queryStr
	 *            查询语句。
	 * @param params
	 *            参数值。
	 */
	public void deleteFromQuery(String queryStr, Map<?, ?>... map) {
		List<?> result = this.find(queryStr, map);
		deleteAll(result);
	}

	/**
	 * 直接运行SQL更新语句
	 * 
	 * @param sql
	 */
	public void runSqlUpdate(String sql) {
		SQLQuery query = getSession().createSQLQuery(sql);
		query.executeUpdate();
	}

	/**
	 * 获取总查询结果总记录数
	 * 
	 * @param queryString
	 * @param params
	 * @return
	 */
	// public long getRowCount(String queryString, final Object[] params) {
	public long getRowCount(String queryString, final Map<?, ?>... map) {
		String countSql = createCountQL(queryString);
		Query query = getSession().createQuery(countSql);

		// for (Integer i = 0; i < map.length; i++) {
		// query.setParameter(i, params[i]);
		// }
		exeParamMap(query, map);

		Iterator<?> iter = query.iterate();
		Number countValue = null;
		/*
		 * //为了规避group by的问题做的变通 if (iter.hasNext()) { countValue = (Number)
		 * iter.next(); } if (countValue == null) { return 0; } return
		 * countValue.longValue();
		 */

		// 以下是李波20150624打的补丁。
		Integer cursor = 0;
		Object obj;
		while (iter.hasNext()) {
			obj = iter.next();
			if (0 == cursor) {
				countValue = (Number) obj;
			}
			cursor++;
		}
		switch (cursor) {
		case 0:
			return 0;
		case 1:
			return countValue.longValue();
		default:
			return cursor.longValue();
		}

	}

	/**
	 * 创建记数的查询语句.
	 * 
	 * @param queryStr
	 * @return
	 */
	private String createCountQL(String queryStr) {
		int idxF = queryStr.indexOf("from");
		int idxD = queryStr.indexOf("distinct");
		int idxG = queryStr.indexOf("group");// libo 20150624 group by的处理
		int idxW = queryStr.indexOf("where");// libo 20150624 group by的处理
		/*
		 * if(idxG>idxW){//说明where 后有group by子句。 return
		 * "select count(*) from ("+queryStr+") as temp"; }else
		 */
		if (idxD > 0 && idxD < 12) {
			String result = queryStr
					.substring(idxD + "distinct".length(), idxF);

			return "select distinct count(" + result + ") "
					+ queryStr.substring(idxF);
		} else {
			return "select count(*) " + queryStr.substring(idxF);
		}
	}

	private List<?> find(String queryStr, Map<?, ?>... map) {
		List<?> result = new ArrayList<Object>();
		Query query = getSession().createQuery(queryStr);
		exeParamMap(query, map);
		result = query.list();
		return result;
	}

	private List<?> find(String queryStr, PageBean pageBean, Map<?, ?>... map) {
		List<?> result = new ArrayList<Object>();
		Query query = getSession().createQuery(queryStr);
		exeParamMap(query, map);
		query.setFirstResult(pageBean.getCurrentPageFirstRecord());
		query.setMaxResults(pageBean.getCurrentPageSize());
		result = query.list();
		return result;
	}

	private void exeParamMap(Query query, Map<?, ?>... map) {
		if (!GodUtils.CheckNull(map)) {
			Iterator<?> it = map[0].keySet().iterator();
			while (it.hasNext()) {
				String key = (String) it.next();
				Object value = (Object) map[0].get(key);
				query.setParameter(key, value);
			}
		}
	}
}
